//Author: Ferdinand Eisenkeil, Soeren Pirk
//Date  : 23.04.2014

#include "Box.h"
#include "VertexBufferObjectAttribs.h"
#include "Shader.h"

Box::Box()
: m_color(0.0f, 0.0f, 0.0f),
  m_position(0.0f, 0.0f, 0.0f),
  m_scale(0.0f, 0.0f, 0.0f)
{    
    init();
}

Box::Box(vec3 pos, vec3 scale, vec3 color)
: m_color(color),
  m_position(pos),
  m_scale(scale)
{    
    init();
}

Box::~Box()
{
}

void Box::init()
{
    buildVBO(vec3(-1.0f, -1.0f, -1.0f), vec3(1.0f, 1.0f, 1.0f), m_color.x, m_color.y, m_color.z, 1.0f);

    m_shader = new Shader("../Shader/Default33.vert.glsl", "../Shader/Default33.frag.glsl");
}

void Box::render(const Transform &trans)
{
    mat4 projection = trans.projection;
    mat4 view = trans.view;
    mat4 model = mat4::identitiy();

    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);

    vec3 camPos = getCamPosFromModelView(trans);

    m_shader->bind();
	
        model = mat4::translate(m_position) * mat4::scale(m_scale);
        mat4 normal = mat3(view * model).inverse().transpose();

        m_shader->setMatrix("matProjection", projection, GL_TRUE);
        m_shader->setMatrix("matView", view, GL_TRUE);
        m_shader->setMatrix("matModel", model, GL_TRUE); 
        m_shader->set3f("camPos", camPos);
		m_shader->seti("culling", 0);

        m_vbo->render();

    m_shader->release();

    glPopClientAttrib();
    glPopAttrib();
}

void Box::buildVBO(const vec3 &mi, const vec3 &ma, float red, float green, float blue, float alpha)
{
    vector<vec3> vertices;
    vector<vec3> normals;

    vertices.push_back(vec3(mi.x, ma.y, mi.z));
    vertices.push_back(vec3(mi.x, ma.y, ma.z));
    vertices.push_back(vec3(ma.x, ma.y, ma.z));
    vertices.push_back(vec3(ma.x, ma.y, mi.z));
    vertices.push_back(vec3(mi.x, mi.y, mi.z));
    vertices.push_back(vec3(ma.x, mi.y, mi.z));
    vertices.push_back(vec3(ma.x, mi.y, ma.z));
    vertices.push_back(vec3(mi.x, mi.y, ma.z));
    vertices.push_back(vec3(mi.x, mi.y, mi.z));
    vertices.push_back(vec3(mi.x, ma.y, mi.z));
    vertices.push_back(vec3(ma.x, ma.y, mi.z));
    vertices.push_back(vec3(ma.x, mi.y, mi.z));
    vertices.push_back(vec3(mi.x, mi.y, ma.z));
    vertices.push_back(vec3(ma.x, mi.y, ma.z));
    vertices.push_back(vec3(ma.x, ma.y, ma.z));
    vertices.push_back(vec3(mi.x, ma.y, ma.z));
    vertices.push_back(vec3(mi.x, mi.y, mi.z));
    vertices.push_back(vec3(mi.x, mi.y, ma.z));
    vertices.push_back(vec3(mi.x, ma.y, ma.z));
    vertices.push_back(vec3(mi.x, ma.y, mi.z));
    vertices.push_back(vec3(ma.x, mi.y, mi.z));
    vertices.push_back(vec3(ma.x, ma.y, mi.z));
    vertices.push_back(vec3(ma.x, ma.y, ma.z));
    vertices.push_back(vec3(ma.x, mi.y, ma.z));

    normals.push_back(vec3(0, 1, 0));
    normals.push_back(vec3(0, 1, 0));
    normals.push_back(vec3(0, 1, 0));
    normals.push_back(vec3(0, 1, 0));
    normals.push_back(vec3(0, -1, 0));
    normals.push_back(vec3(0, -1, 0));
    normals.push_back(vec3(0, -1, 0));
    normals.push_back(vec3(0, -1, 0));
    normals.push_back(vec3(0, 0, -1));
    normals.push_back(vec3(0, 0, -1));
    normals.push_back(vec3(0, 0, -1));
    normals.push_back(vec3(0, 0, -1));
    normals.push_back(vec3(0, 0, 1));
    normals.push_back(vec3(0, 0, 1));
    normals.push_back(vec3(0, 0, 1));
    normals.push_back(vec3(0, 0, 1));
    normals.push_back(vec3(-1, 0, 0));
    normals.push_back(vec3(-1, 0, 0));
    normals.push_back(vec3(-1, 0, 0));
    normals.push_back(vec3(-1, 0, 0));
    normals.push_back(vec3(1, 0, 0));
    normals.push_back(vec3(1, 0, 0));
    normals.push_back(vec3(1, 0, 0));
    normals.push_back(vec3(1, 0, 0));


   int nrVertices = vertices.size();
   VertexBufferObjectAttribs::DATA *attrData = new VertexBufferObjectAttribs::DATA[nrVertices];

    for(int i=0; i<nrVertices; ++i)
    {    
        vec3 v = vertices[i];
        vec3 n = normals[i];

        attrData[i].vx = v.x;
        attrData[i].vy = v.y;
        attrData[i].vz = v.z;
        attrData[i].vw = 1.0f;

        attrData[i].nx = n.x;
        attrData[i].ny = n.y;
        attrData[i].nz = n.z;
        attrData[i].nw = 1.0f;

        attrData[i].cx = red;
        attrData[i].cy = green;
        attrData[i].cz = blue;
        attrData[i].cw = alpha;

        attrData[i].tx = 0.0f;
        attrData[i].ty = 0.0f;
        attrData[i].tz = 0.0f;
        attrData[i].tw = 0.0f;
    }

    VertexBufferObjectAttribs *vbo = new VertexBufferObjectAttribs();
    vbo->setData(attrData, GL_STATIC_DRAW, nrVertices, GL_QUADS);

    vbo->addAttrib(VERTEX_POSITION);
    vbo->addAttrib(VERTEX_NORMAL);
    vbo->addAttrib(VERTEX_COLOR);
    vbo->addAttrib(VERTEX_TEXTURE);
    vbo->bindAttribs();

    delete[] attrData;    

    m_vbo = vbo;
}

void Box::reloadShader()
{	
	delete m_shader;
	m_shader = new Shader("../Shader/Default33.vert.glsl", "../Shader/Default33.frag.glsl");
}